#include "OgreAMLDemoPrecompiledHeader.h"

#include <OgreAMLDemo.h>

#include <OgreRoot.h>
#include <OgreTextureManager.h>
#include <OgreResourceGroupManager.h>
#include <OgreRenderWindow.h>
#include <OgreSceneManager.h>
#include <OgreCamera.h>
#include <OgreViewport.h>
#include <OgreConfigFile.h>
#include <OgreEntity.h>

namespace OgreAMLDemo
{

//-------------------------------------------------------------------------------------------------------------------------------------------------
Application::Application()
: mRoot(NULL)
, mObjectsNode(NULL)
{
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
Application::~Application()
{
	// destroy ogre instance
	OGRE_DELETE_T( mRoot, Root, Ogre::MEMCATEGORY_GENERAL );
	mRoot = NULL;
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
void Application::go()
{
	if( !setup() )
		return;

	// begin rendering loop
	mRoot->startRendering();
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
bool Application::setup()
{
#if OGRE_DEBUG_MODE
	Ogre::String pluginsfile = "plugins_d.cfg";
#else
	Ogre::String pluginsfile = "plugins.cfg";
#endif

	// Create new ogre instance
	mRoot = OGRE_NEW_T( Ogre::Root, Ogre::MEMCATEGORY_GEOMETRY )( pluginsfile );

	setupResources();

	// Show the configuration dialog
	if( !mRoot->showConfigDialog() )
		return false;

	// Initialise the system
	mWindow = mRoot->initialise( true );
	// Register frame listener
	mRoot->addFrameListener( this );
	
	//Register as a Window listener
	Ogre::WindowEventUtilities::addWindowEventListener( mWindow, this );

	// create the SceneManager, in this case a generic one
	mSceneMgr = mRoot->createSceneManager( Ogre::ST_GENERIC );


	// create the camera
	mCamera = mSceneMgr->createCamera( "DemoCamera" );
	// position it at 500 in Z direction
	mCamera->setPosition( Ogre::Vector3::UNIT_Z * Ogre::Real(500.0) );
	// look back along -Z
	mCamera->lookAt( Ogre::Vector3::NEGATIVE_UNIT_Z * Ogre::Real(300.0));
	mCamera->setNearClipDistance( 5 );


	// create one viewport, entire window
	Ogre::Viewport* viewport = mWindow->addViewport( mCamera );
	// Set greay background colour
	viewport->setBackgroundColour( Ogre::ColourValue( 0.5f, 0.5f, 0.5f ) );
	
	mCamera->setAspectRatio( Ogre::Real(viewport->getActualWidth()) /
		Ogre::Real(viewport->getActualHeight()) );
	
	// Set wireframe mode
	mCamera->setPolygonMode( Ogre::PM_WIREFRAME );


	// Set default mipmap level
	Ogre::TextureManager::getSingleton().setDefaultNumMipmaps( 5 );


	// Initialise, parse scripts etc
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
	
	// Create the scene
	createScene();
	
	return true;
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
void Application::setupResources()
{
	// load resource paths from config file
	Ogre::ConfigFile cf;
#if OGRE_DEBUG_MODE
	cf.load( "resources_d.cfg" );
#else
	cf.load( "resources.cfg" );
#endif

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while( seci.hasMoreElements() )
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for( i = settings->begin(); i != settings->end(); ++i )
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName );
		}
	}
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
void Application::createScene()
{
	// Create main SceneNode
	mObjectsNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "ObjectsNode" );



	// Create SceneNode for sphere1
	Ogre::SceneNode* sphereNode = mObjectsNode->createChildSceneNode( "SphereNode1" );

	// Create sphere 1
	Ogre::Entity* sphere = mSceneMgr->createEntity( "sphere1" );

	// Add sphere 1 to world
	sphereNode->attachObject( sphere );

	// Set sphere position and size
	sphereNode->setPosition( 200, 0.0, 0.0 );
	sphereNode->setScale( Ogre::Vector3::UNIT_SCALE * Ogre::Real(0.3) );

	// Update bounds
	sphereNode->_updateBounds();




	// Create SceneNode for sphere2
	sphereNode = mObjectsNode->createChildSceneNode( "SphereNode2" );

	// Create sphere 2
	sphere = mSceneMgr->createEntity( "sphere2" );

	// Add sphere to world
	sphereNode->attachObject( sphere );

	// Set sphere position and size
	sphereNode->setPosition( -200, 0.0, 0.0 );
	sphereNode->setScale( Ogre::Vector3::UNIT_SCALE * Ogre::Real(0.3) );

	// Update bounds
	sphereNode->_updateBounds();




	// Update bounds
	mObjectsNode->_updateBounds();
} 

//-------------------------------------------------------------------------------------------------------------------------------------------------
void Application::windowClosed( Ogre::RenderWindow* rw )
{
	// Stop rendering loop when render window is closed
	if( rw != mWindow )
		return;

	mRoot->queueEndRendering();
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
bool Application::frameStarted( const Ogre::FrameEvent& evt )
{
	// Calc object roration
	Ogre::Quaternion q(1.0, 0.0, Ogre::Math::PI * Ogre::Real(0.1) * evt.timeSinceLastFrame, 0.0);
	Ogre::Quaternion rotation = mObjectsNode->getOrientation() * q;

	// Rotate main node
	mObjectsNode->setOrientation( rotation );

	return true;
}

//-------------------------------------------------------------------------------------------------------------------------------------------------
void Application::windowResized( Ogre::RenderWindow* rw )
{
	if( !mCamera || rw != mWindow )
		return;

	Ogre::Viewport* viewport = mCamera->getViewport();
	if( !viewport )
		return;

	mCamera->setAspectRatio( Ogre::Real(viewport->getActualWidth()) /
		Ogre::Real(viewport->getActualHeight()) );
}

} // end of namespace OgreAMLDemo
